#include "led_matrix.h"

/* Indication flag to whether the led matrix driver has finished drawing
   the frames of the current buffer. 0 if there is nothing left to be drawn. */
static unsigned int _led_matrix_frames_left_to_draw = 0;

/* The current row, in the current buffer, being drawn by the led matrix driver
*/
static unsigned int _led_matrix_current_row = 0;

/* The led matrix driver is double buffered. These buffers must be provided 
   by the user software in the init function */
static unsigned char *_led_matrix_buffer1 = 0; 
static unsigned char *_led_matrix_buffer2 = 0;

/* Current buffer being drawn by the led matrix driver */
static unsigned char  *_led_matrix_current_busy_buffer = 0;

/* led matrix size: rows and columns */
static unsigned int _led_matrix_rows = 0;
static unsigned int _led_matrix_cols = 0;

/* User software function for turning a single led on */
static void (*_led_matrix_turn_on_singe_led)(unsigned int, unsigned int) = 0;

/* User software function for turning off all leds */
static void (*_led_matrix_turn_off_all_leds)(void) = 0;

/*----------------------------------------------------------------------------*/

void led_matrix_init( unsigned char *buffer1,
                      unsigned char *buffer2,
                      unsigned int rows, unsigned int cols, 
                      void (*turn_on_singe_led)(unsigned int, unsigned int),
                      void (*turn_off_all_leds)(void) ){
	_led_matrix_frames_left_to_draw = 0;

	_led_matrix_buffer1                = buffer1;
	_led_matrix_buffer2                = buffer2;
	_led_matrix_rows                   = rows;
	_led_matrix_cols                   = cols;
	_led_matrix_turn_on_singe_led      = turn_on_singe_led;
	_led_matrix_turn_off_all_leds      = turn_off_all_leds;

	_led_matrix_current_row            = 0;
	_led_matrix_current_busy_buffer    = buffer1;
}

void led_matrix_update( void ){
	unsigned int col = 0;
 	_led_matrix_turn_off_all_leds( );
	if (_led_matrix_frames_left_to_draw == 0){
		return;
	}

	for (col = 0; col < _led_matrix_cols; col += 1){
		if ( _led_matrix_current_busy_buffer[ 
			(_led_matrix_current_row * _led_matrix_cols) + col ] ){
			_led_matrix_turn_on_singe_led( _led_matrix_current_row, col );
		}
	}
	if ( _led_matrix_current_row == (_led_matrix_rows - 1) ){
	 	_led_matrix_current_row = 0;
	 	_led_matrix_frames_left_to_draw -= 1;
	}
	else{
		_led_matrix_current_row += 1;
	}
}

unsigned int led_matrix_is_ready( void ){
	if (_led_matrix_frames_left_to_draw == 0){
		return 1;
	}
	else{
		return 0;
	}
}
	
unsigned char *led_matrix_get_empty_buffer( void ){
	unsigned int i = 0;
	unsigned char *empty_buffer = 0;
	if ( _led_matrix_current_busy_buffer == _led_matrix_buffer1 ){
		empty_buffer = _led_matrix_buffer2;
	}
	else{
		empty_buffer = _led_matrix_buffer1;
	}

	for(i = 0; i < (_led_matrix_rows * _led_matrix_cols); i += 1){
			empty_buffer[i] = 0;
	}

	return empty_buffer;
}

void led_matrix_draw( unsigned int frames ){
	if ( _led_matrix_current_busy_buffer == _led_matrix_buffer1 ){
		_led_matrix_current_busy_buffer = _led_matrix_buffer2;
	}
	else{
		_led_matrix_current_busy_buffer = _led_matrix_buffer1;
	}
	_led_matrix_frames_left_to_draw = frames;
}
